// VS Code 扩展 API 模块
const vscode = require('vscode');
const fs = require('fs');
const path = require('path');
const { spawn } = require('child_process');
const os = require('os');

/**
 * 插件激活函数 - 当插件第一次被使用时调用
 * @param {vscode.ExtensionContext} context
 */
function activate(context) {
	console.log('Context Engine 插件已激活!');

	// 创建 Webview 视图提供器
	const ContextEngineViewProvider = require('./src/webviewProvider');
	const provider = new ContextEngineViewProvider(context);

	// 注册 Webview 视图提供器
	context.subscriptions.push(
		vscode.window.registerWebviewViewProvider('context-engine-main', provider)
	);

	// 注册主要命令：发送到 Copilot
	const disposable = vscode.commands.registerCommand('copilot-agent-bridge.sendToCopilot', async function () {
		try {
			await sendToCopilot();
		} catch (error) {
			console.error('发送到 Copilot 时出错:', error);
			await handleError(error);
		}
	});

	// 注册配置命令：打开设置
	const configDisposable = vscode.commands.registerCommand('copilot-agent-bridge.openSettings', function () {
		vscode.commands.executeCommand('workbench.action.openSettings', 'contextEngine');
	});

	// 注册面板相关命令
	const refreshDisposable = vscode.commands.registerCommand('copilot-agent-bridge.refreshPanel', function () {
		provider.refresh();
	});

	const clearHistoryDisposable = vscode.commands.registerCommand('copilot-agent-bridge.clearHistory', function () {
		provider.clearHistory();
	});

	const openPanelDisposable = vscode.commands.registerCommand('copilot-agent-bridge.openPanel', async function () {
		// 先打开视图
		await vscode.commands.executeCommand('workbench.view.extension.context-engine-panel');
		// 然后尝试将其移动到右侧（如果支持的话）
		try {
			await vscode.commands.executeCommand('workbench.action.moveSideBarRight');
		} catch (error) {
			// 忽略错误，某些版本的 VS Code 可能不支持这个命令
			console.log('无法移动侧边栏到右侧:', error.message);
		}
	});

	context.subscriptions.push(
		disposable,
		configDisposable,
		refreshDisposable,
		clearHistoryDisposable,
		openPanelDisposable
	);

	// Initialize configuration validation
	activateValidation(context);
}

/**
 * 主要功能：处理发送代码到 Copilot 的流程
 */
async function sendToCopilot() {
	const editor = vscode.window.activeTextEditor;
	if (!editor) {
		vscode.window.showWarningMessage('未找到活动编辑器，请先打开一个文件。');
		return;
	}

	// 步骤1：显示范围选择快速选择框
	const selectedRange = await showRangeSelection(editor);
	if (!selectedRange) {
		return; // 用户取消了操作
	}

	// 步骤2：显示提示输入框
	const userPrompt = await showPromptInput();
	if (userPrompt === undefined) {
		return; // 用户取消了操作
	}

	// 步骤3：生成 context.txt 内容
	const contextContent = generateContextContent(editor, selectedRange, userPrompt);

	// 步骤4：保存 context.txt 并上传到 Edge Copilot
	await uploadToCopilot(contextContent);
}

/**
 * Show range selection QuickPick
 * @param {vscode.TextEditor} editor
 * @returns {Promise<{type: string, range: vscode.Range, text: string} | undefined>}
 */
async function showRangeSelection(editor) {
	const hasSelection = !editor.selection.isEmpty;
	const document = editor.document;

	const items = [
		{
			label: '📄 Current File',
			description: `Entire file (${document.lineCount} lines)`,
			detail: 'Send the complete current file',
			type: 'file'
		},
		{
			label: '✂️ Selected Text Only',
			description: hasSelection ? `${editor.selection.end.line - editor.selection.start.line + 1} lines selected` : 'No text selected',
			detail: 'Send only the currently selected text',
			type: 'selection',
			disabled: !hasSelection
		},
		{
			label: '🧩 Visible Editor (500 lines)',
			description: 'Current viewport area',
			detail: 'Send the currently visible code in the editor',
			type: 'visible'
		}
	];

	// Filter out disabled items
	const enabledItems = items.filter(item => !item.disabled);

	const selected = await vscode.window.showQuickPick(enabledItems, {
		placeHolder: 'Select code range to send to Copilot',
		canPickMany: false,
		ignoreFocusOut: false
	});

	if (!selected) {
		return undefined;
	}

	let range, text;
	const config = vscode.workspace.getConfiguration('copilotAgentBridge');
	const maxLines = config.get('maxFileSize', 10000);

	switch (selected.type) {
		case 'file':
			range = new vscode.Range(0, 0, document.lineCount - 1, document.lineAt(document.lineCount - 1).text.length);
			text = document.getText(range);
			// Truncate if too large
			if (document.lineCount > maxLines) {
				const truncatedRange = new vscode.Range(0, 0, maxLines - 1, document.lineAt(maxLines - 1).text.length);
				text = document.getText(truncatedRange) + `\n\n... (File truncated at ${maxLines} lines. Total: ${document.lineCount} lines)`;
				range = truncatedRange;
			}
			break;

		case 'selection':
			range = editor.selection;
			text = document.getText(range);
			break;

		case 'visible':
			const visibleRanges = editor.visibleRanges;
			if (visibleRanges.length > 0) {
				// Get the first visible range and extend it to include up to 500 lines
				const startLine = visibleRanges[0].start.line;
				const endLine = Math.min(startLine + 500, document.lineCount - 1);
				range = new vscode.Range(startLine, 0, endLine, document.lineAt(endLine).text.length);
				text = document.getText(range);
			} else {
				// Fallback to current cursor position
				const currentLine = editor.selection.active.line;
				const startLine = Math.max(0, currentLine - 250);
				const endLine = Math.min(currentLine + 250, document.lineCount - 1);
				range = new vscode.Range(startLine, 0, endLine, document.lineAt(endLine).text.length);
				text = document.getText(range);
			}
			break;

		default:
			return undefined;
	}

	return {
		type: selected.type,
		range: range,
		text: text
	};
}

/**
 * Show prompt input box
 * @returns {Promise<string | undefined>}
 */
async function showPromptInput() {
	const prompt = await vscode.window.showInputBox({
		title: 'Additional prompt for Copilot (optional)',
		placeHolder: 'Explain this code / Generate unit tests / Refactor...',
		prompt: 'Enter your prompt for Copilot (optional)',
		ignoreFocusOut: true,
		value: ''
	});

	return prompt; // Can be empty string or undefined (cancelled)
}

/**
 * Generate context content for Copilot
 * @param {vscode.TextEditor} editor
 * @param {{type: string, range: vscode.Range, text: string}} selectedRange
 * @param {string} userPrompt
 * @returns {string}
 */
function generateContextContent(editor, selectedRange, userPrompt) {
	const document = editor.document;
	const fileName = path.basename(document.fileName);
	const language = document.languageId;
	const config = vscode.workspace.getConfiguration('copilotAgentBridge');
	const template = config.get('promptTemplate', 'Please analyze the following code:\n\n{code}\n\n{prompt}');

	// Build the context information
	const contextInfo = [
		`File: ${fileName}`,
		`Language: ${language}`,
		`Range: ${getRangeDescription(selectedRange)}`,
		`Lines: ${selectedRange.range.start.line + 1}-${selectedRange.range.end.line + 1}`,
		`Timestamp: ${new Date().toISOString()}`,
		''
	].join('\n');

	// Format the code block
	const codeBlock = `\`\`\`${language}\n${selectedRange.text}\n\`\`\``;

	// Apply template
	let content = template
		.replace('{code}', codeBlock)
		.replace('{prompt}', userPrompt || '');

	// Add context information at the beginning
	content = contextInfo + content;

	return content;
}

/**
 * Get human-readable description of the selected range
 * @param {{type: string, range: vscode.Range, text: string}} selectedRange
 * @returns {string}
 */
function getRangeDescription(selectedRange) {
	switch (selectedRange.type) {
		case 'file':
			return 'Entire file';
		case 'selection':
			return 'Selected text';
		case 'visible':
			return 'Visible editor area';
		default:
			return 'Unknown range';
	}
}

/**
 * Upload context to Edge Copilot
 * @param {string} contextContent
 */
async function uploadToCopilot(contextContent) {
	try {
		// Create temporary file
		const tempDir = os.tmpdir();
		const tempFilePath = path.join(tempDir, `copilot-context-${Date.now()}.txt`);

		// Write content to temporary file
		fs.writeFileSync(tempFilePath, contextContent, 'utf8');

		// Show progress
		await vscode.window.withProgress({
			location: vscode.ProgressLocation.Notification,
			title: "Sending to Copilot...",
			cancellable: false
		}, async (progress) => {
			progress.report({ increment: 30, message: "Creating context file..." });

			// Get Edge path
			const edgePath = await getEdgePath();
			if (!edgePath) {
				throw new Error('Microsoft Edge not found. Please install Edge or configure the path in settings.');
			}

			progress.report({ increment: 30, message: "Opening Edge Copilot..." });

			// Open Edge with Copilot and the file
			await openEdgeWithFile(edgePath, tempFilePath);

			progress.report({ increment: 40, message: "Done!" });

			// Clean up temp file after a delay
			setTimeout(() => {
				try {
					if (fs.existsSync(tempFilePath)) {
						fs.unlinkSync(tempFilePath);
					}
				} catch (error) {
					console.warn('Failed to clean up temp file:', error);
				}
			}, 30000); // 30 seconds delay
		});

		vscode.window.showInformationMessage('Context sent to Edge Copilot successfully!');

	} catch (error) {
		console.error('Error uploading to Copilot:', error);
		vscode.window.showErrorMessage(`Failed to send to Copilot: ${error.message}`);
		throw error;
	}
}

/**
 * Get Microsoft Edge executable path
 * @returns {Promise<string | null>}
 */
async function getEdgePath() {
	const config = vscode.workspace.getConfiguration('copilotAgentBridge');
	const configuredPath = config.get('edgePath', '');

	if (configuredPath && fs.existsSync(configuredPath)) {
		return configuredPath;
	}

	// Auto-detect Edge path based on platform
	const platform = os.platform();
	const possiblePaths = [];

	if (platform === 'win32') {
		possiblePaths.push(
			'C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe',
			'C:\\Program Files\\Microsoft\\Edge\\Application\\msedge.exe',
			path.join(os.homedir(), 'AppData\\Local\\Microsoft\\Edge\\Application\\msedge.exe')
		);
	} else if (platform === 'darwin') {
		possiblePaths.push(
			'/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge'
		);
	} else {
		possiblePaths.push(
			'/usr/bin/microsoft-edge',
			'/usr/bin/microsoft-edge-stable',
			'/opt/microsoft/msedge/msedge'
		);
	}

	for (const edgePath of possiblePaths) {
		if (fs.existsSync(edgePath)) {
			return edgePath;
		}
	}

	return null;
}

/**
 * Open Edge with the context file
 * @param {string} edgePath
 * @param {string} filePath
 */
async function openEdgeWithFile(edgePath, filePath) {
	return new Promise((resolve, reject) => {
		// Copilot URL
		const copilotUrl = 'https://copilot.microsoft.com/';

		// Launch Edge with Copilot
		const edgeProcess = spawn(edgePath, [
			'--new-window',
			copilotUrl
		], {
			detached: true,
			stdio: 'ignore'
		});

		edgeProcess.on('error', (error) => {
			reject(new Error(`Failed to launch Edge: ${error.message}`));
		});

		// Don't wait for Edge to close
		edgeProcess.unref();

		// Give Edge time to start, then show instructions
		setTimeout(() => {
			vscode.window.showInformationMessage(
				`Edge Copilot opened! Please drag and drop the file: ${filePath}`,
				'Copy File Path'
			).then(selection => {
				if (selection === 'Copy File Path') {
					vscode.env.clipboard.writeText(filePath);
					vscode.window.showInformationMessage('File path copied to clipboard!');
				}
			});
			resolve();
		}, 2000);
	});
}

/**
 * Handle errors with user-friendly messages and retry options
 * @param {Error} error
 */
async function handleError(error) {
	let message = 'An unexpected error occurred.';
	let actions = ['OK'];

	if (error.message.includes('No active editor')) {
		message = 'Please open a file first before sending to Copilot.';
	} else if (error.message.includes('Microsoft Edge not found')) {
		message = 'Microsoft Edge is required but not found. Please install Edge or configure the path in settings.';
		actions = ['Open Settings', 'OK'];
	} else if (error.message.includes('Failed to launch Edge')) {
		message = 'Failed to launch Microsoft Edge. Please check your Edge installation.';
		actions = ['Retry', 'Open Settings', 'OK'];
	} else if (error.message.includes('File truncated')) {
		message = `File is too large and was truncated. You can adjust the limit in settings.`;
		actions = ['Open Settings', 'OK'];
	} else {
		message = `Failed to send to Copilot: ${error.message}`;
		actions = ['Retry', 'OK'];
	}

	const selection = await vscode.window.showErrorMessage(message, ...actions);

	switch (selection) {
		case 'Retry':
			try {
				await sendToCopilot();
			} catch (retryError) {
				console.error('Retry failed:', retryError);
				vscode.window.showErrorMessage(`Retry failed: ${retryError.message}`);
			}
			break;
		case 'Open Settings':
			vscode.commands.executeCommand('workbench.action.openSettings', 'copilotAgentBridge');
			break;
	}
}

/**
 * Validate configuration and show warnings if needed
 */
function validateConfiguration() {
	const config = vscode.workspace.getConfiguration('copilotAgentBridge');
	const edgePath = config.get('edgePath', '');
	const maxFileSize = config.get('maxFileSize', 10000);

	if (edgePath && !fs.existsSync(edgePath)) {
		vscode.window.showWarningMessage(
			'Configured Edge path does not exist. Auto-detection will be used instead.',
			'Open Settings'
		).then(selection => {
			if (selection === 'Open Settings') {
				vscode.commands.executeCommand('workbench.action.openSettings', 'copilotAgentBridge.edgePath');
			}
		});
	}

	if (maxFileSize < 100 || maxFileSize > 50000) {
		vscode.window.showWarningMessage(
			'Max file size should be between 100 and 50,000 lines for optimal performance.',
			'Open Settings'
		).then(selection => {
			if (selection === 'Open Settings') {
				vscode.commands.executeCommand('workbench.action.openSettings', 'copilotAgentBridge.maxFileSize');
			}
		});
	}
}

// Call validation on activation
function activateValidation(context) {
	// Validate configuration on startup
	validateConfiguration();

	// Watch for configuration changes
	const configWatcher = vscode.workspace.onDidChangeConfiguration(event => {
		if (event.affectsConfiguration('copilotAgentBridge')) {
			validateConfiguration();
		}
	});

	context.subscriptions.push(configWatcher);
}

// This method is called when your extension is deactivated
function deactivate() {}

module.exports = {
	activate,
	deactivate
}
